/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2008-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef DECLARATIONS_H
#define DECLARATIONS_H

#include "actions.h"
#include "cnome.h"
#include "directives.h"
#include "tokens.h"
#include "util.h"

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_dynamic.hpp>

namespace cnome {
template <typename ScannerT>
void
cpp::definition<ScannerT>::declarations(cpp const& self)
    {
        using namespace actions;
        using namespace directive;
        using namespace util;
        
        declaration_seq =
            declaration >> declaration_seq_helper 
        ;

        declaration_seq_helper =
                ( declaration >> declaration_seq_helper ) 
            |
                EPSILON 
        ;

        declaration =
                block_declaration       
            |	function_definition     
            |	template_declaration    
            |	explicit_instantiation  
            |	explicit_specialization 
            |	linkage_specification   
            |	namespace_definition
        ;

        linkage_specification =
                (		EXTERN >> STRINGLIT >> LEFTBRACE >> !declaration_seq 
                    >> RIGHTBRACE ) 
            |   EXTERN >> STRINGLIT >> declaration
        ;
        block_declaration =
            remain_scope_d[
                    simple_declaration         
                |	asm_definition             
                |	namespace_alias_definition 
                |	using_declaration          
                |	using_directive ]
        ;

        asm_definition =
				( ASM >> LEFTPAREN >> STRINGLIT >> RIGHTPAREN )
            // TODO: Implement a negation operator in order to implement a new mechanism to handle a MS asm block
			// alb 07jun2011
			//|	( MSEXT_ASM >> LEFTBRACE >> *(not_p(RIGHTBRACE)) >> RIGHTBRACE )
        ;

        namespace_alias_definition =
                NAMESPACE 
            >>	(    IDENTIFIER >> ASSIGN 
                  >> remain_scope_d[ qualified_namespace_specifier ] 
                )[&newNamespace_Alias]
        ;

        qualified_namespace_specifier =
                sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] >> !nested_name_specifier >> namespace_name ]
            >>	SEMICOLON
        ;

        using_declaration =
            remain_scope_d[
                    (		USING >> !TYPENAME 
                        >> sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope]
                            >>	nested_name_specifier >> unqualified_id_raw ] ) 
                |	( USING >> COLON_COLON[&scopeIsAbsolut][&enter_scope] >> unqualified_id_raw ) ]
        ;

        using_directive =
            remain_scope_d[
                USING >> NAMESPACE 
                >> ( sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] >> !nested_name_specifier 
                       >>	namespace_name ] )[&addUsingDirective] 
            ]
        ;

        simple_declaration =
                remain_type_d [
                        decl_specifier_seq[&newTypeSpc] 
                    >>  !init_declarator_list >> SEMICOLON
                ]
            |	remain_type_d [
                    !init_declarator_list >> SEMICOLON
                ]
        ;

        namespace_definition =
                named_namespace_definition 
            |	unnamed_namespace_definition 
        ;

        namespace_name =
                original_namespace_name 
            |	namespace_alias
        ;

        namespace_alias =
            NAMESPACE_ALIAS // IDENTIFIER
        ;

        named_namespace_definition =
                original_namespace_definition 
            |	extension_namespace_definition
        ;

        extension_namespace_definition =
            remain_scope_d[
                    NAMESPACE >> original_namespace_name[&enter_scope] 
                >>  LEFTBRACE >> ud_d[ namespace_body ] >> RIGHTBRACE ]
        ;

        namespace_body =
            !declaration_seq
        ;

        unnamed_namespace_definition =
            remain_scope_d[
                    NAMESPACE >> EPSILON[&enter_scope] >> LEFTBRACE 
                >>	ud_d[ namespace_body ] >> RIGHTBRACE ]
        ;

        original_namespace_name =
            ORIGINAL_NAMESPACE_NAME // 	IDENTIFIER
        ;

        original_namespace_definition =
            remain_scope_d[
                    NAMESPACE 
                >>	IDENTIFIER[&newOriginal_Namespace_Name][&enter_scope] 
                >>	LEFTBRACE >> ud_d[ namespace_body ] >> RIGHTBRACE[&leaveScope] ]
        ;

        decl_specifier =
            (		storage_class_specifier 
                |	type_specifier          
                |	function_specifier      
                |	FRIEND                  
                |	TYPEDEF
            )[&new_dcl_spc] >> TYPE_DECL_VALID
        ;

        decl_specifier_seq =
            remain_tdc_d[
                decl_specifier >> decl_specifier_seq_helper ] 
        ;

        decl_specifier_seq_helper =
                ( decl_specifier >> decl_specifier_seq_helper ) 
            |	EPSILON
        ;

        storage_class_specifier =
                AUTO     
            |	REGISTER 
            |	STATIC   
            |	EXTERN   
            |	MUTABLE
        ;

        function_specifier =
                INLINE
            |	VIRTUAL
            |	EXPLICIT 
        ;

        type_specifier =
            remain_scope_d[
				typ_d[
                    simple_type_specifier     
                |	class_specifier           
                |	enum_specifier            
                |	elaborated_type_specifier 
                |	cv_qualifier 
				]
			]
        ;

        elaborated_type_specifier =
                (		class_key 
                    >>  sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope]
                        >>	!nested_name_specifier ] >> !TEMPLATE >> template_id ) 
            |   (		class_key 
                    >> sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope]
                          >>	!nested_name_specifier >> (IDENTIFIER[&newClass_Name]|CLASS_NAME) ] ) 
            |	(		ENUM 
                    >> sss_d [ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                          >>	!nested_name_specifier >> (IDENTIFIER|ENUM_NAME)[&newEnum_Name] ] )
            |	(		TYPENAME 
                    >> sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                           >>	nested_name_specifier >> (IDENTIFIER|TYPEDEF_NAME)[&newTypedef_Name] ] ) 
            |	(		TYPENAME 
                    >> sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                           >> nested_name_specifier ] >> TEMPLATE >>  template_id )
        ;

        enum_specifier =
            remain_scope_d[
                    ENUM >> !(IDENTIFIER|ENUM_NAME)[&newEnum_Name][&enter_scope] >> LEFTBRACE 
                >>	enumerator_list >> RIGHTBRACE
            ]
        ;

        enumerator_list =
            enumerator_definition >> enumerator_list_helper
        ;

        enumerator_list_helper =
                ( COMMA >> if_p(lookahead_d[RIGHTBRACE])[EPSILON].else_p[enumerator_definition >> enumerator_list_helper] ) 
            |	EPSILON
        ;

        enumerator_definition =
                ( enumerator >> if_p(lookahead_d[ASSIGN])[NOTHING].else_p[EPSILON] )
            |	( enumerator >> ASSIGN >> constant_expression )
        ;

        enumerator =
            IDENTIFIER[&newEnumerator]
        ;

        simple_type_specifier =
                remain_scope_d[
                        sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                            >>	!nested_name_specifier 
                            >>  type_name ] 
                    >>  if_p(lookahead_d[assignment_operator])[NOTHING].
                        else_p[EPSILON]
                ]
            |	remain_scope_d[
                    (  sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                           >> nested_name_specifier ] >> TEMPLATE >> template_id ) ]
            |	CHAR_     
            |	WCHART   
            |	BOOL_ 
            |	SHORT_
            |	INT_
            |	LONG_  
            |	SIGNED
            |	UNSIGNED
            |	FLOAT_
            |	DOUBLE_
            |	VOID_
        ;

        typedef_name =
            TYPEDEF_NAME // IDENTIFIER
        ;

        type_name =
                class_name   
            |	enum_name    
            |	typedef_name
        ;

        enum_name =
            ENUM_NAME // IDENTIFIER
        ;
        //  End grammar definition
          
        // turn on the debugging info.
        BOOST_SPIRIT_DEBUG_RULE(declaration_seq);
        BOOST_SPIRIT_DEBUG_RULE(declaration_seq_helper);
        BOOST_SPIRIT_DEBUG_RULE(declaration);
        BOOST_SPIRIT_DEBUG_RULE(block_declaration);
        BOOST_SPIRIT_DEBUG_RULE(function_definition);
        BOOST_SPIRIT_DEBUG_RULE(template_declaration);
        BOOST_SPIRIT_DEBUG_RULE(explicit_instantiation);
        BOOST_SPIRIT_DEBUG_RULE(explicit_specialization);
        BOOST_SPIRIT_DEBUG_RULE(linkage_specification);
        BOOST_SPIRIT_DEBUG_RULE(namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
        BOOST_SPIRIT_DEBUG_RULE(namespace_name);
        BOOST_SPIRIT_DEBUG_RULE(block_declaration);
        BOOST_SPIRIT_DEBUG_RULE(simple_declaration);
        BOOST_SPIRIT_DEBUG_RULE(asm_definition);
        BOOST_SPIRIT_DEBUG_RULE(namespace_alias_definition);
        BOOST_SPIRIT_DEBUG_RULE(qualified_namespace_specifier);
        BOOST_SPIRIT_DEBUG_RULE(using_declaration);
        BOOST_SPIRIT_DEBUG_RULE(using_directive);
        BOOST_SPIRIT_DEBUG_RULE(simple_declaration);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
        BOOST_SPIRIT_DEBUG_RULE(init_declarator_list);
        BOOST_SPIRIT_DEBUG_RULE(using_directive);
        BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
        BOOST_SPIRIT_DEBUG_RULE(namespace_name);
        BOOST_SPIRIT_DEBUG_RULE(namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(named_namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(unnamed_namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(namespace_name);
        BOOST_SPIRIT_DEBUG_RULE(original_namespace_name);
        BOOST_SPIRIT_DEBUG_RULE(namespace_alias);
        BOOST_SPIRIT_DEBUG_RULE(named_namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(original_namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(original_namespace_name);
        BOOST_SPIRIT_DEBUG_RULE(namespace_body);
        BOOST_SPIRIT_DEBUG_RULE(extension_namespace_definition);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq_helper);
        BOOST_SPIRIT_DEBUG_RULE(decl_specifier);
        BOOST_SPIRIT_DEBUG_RULE(init_declarator_list);
        BOOST_SPIRIT_DEBUG_RULE(storage_class_specifier);
        BOOST_SPIRIT_DEBUG_RULE(type_specifier);
        BOOST_SPIRIT_DEBUG_RULE(function_specifier);
        BOOST_SPIRIT_DEBUG_RULE(type_specifier);
        BOOST_SPIRIT_DEBUG_RULE(simple_type_specifier);
        BOOST_SPIRIT_DEBUG_RULE(class_specifier);
        BOOST_SPIRIT_DEBUG_RULE(enum_specifier);
        BOOST_SPIRIT_DEBUG_RULE(elaborated_type_specifier);
        BOOST_SPIRIT_DEBUG_RULE(cv_qualifier);
        BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
        BOOST_SPIRIT_DEBUG_RULE(template_id);
        BOOST_SPIRIT_DEBUG_RULE(class_name);
        BOOST_SPIRIT_DEBUG_RULE(enum_name);  
        BOOST_SPIRIT_DEBUG_RULE(class_key);
        BOOST_SPIRIT_DEBUG_RULE(enumerator_list);
        BOOST_SPIRIT_DEBUG_RULE(enumerator_list_helper);
        BOOST_SPIRIT_DEBUG_RULE(enumerator_definition);
        BOOST_SPIRIT_DEBUG_RULE(enumerator);
        BOOST_SPIRIT_DEBUG_RULE(constant_expression);
        BOOST_SPIRIT_DEBUG_RULE(simple_type_specifier);
        BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
        BOOST_SPIRIT_DEBUG_RULE(type_name);
        BOOST_SPIRIT_DEBUG_RULE(template_id);
        BOOST_SPIRIT_DEBUG_RULE(type_name);
        BOOST_SPIRIT_DEBUG_RULE(class_name);
        BOOST_SPIRIT_DEBUG_RULE(typedef_name);

        BOOST_SPIRIT_DEBUG_RULE(CLASS_NAME);
        BOOST_SPIRIT_DEBUG_RULE(ENUM_NAME);
        BOOST_SPIRIT_DEBUG_RULE(TYPEDEF_NAME);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE_ALIAS);
        BOOST_SPIRIT_DEBUG_RULE(ORIGINAL_NAMESPACE_NAME);

        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
        BOOST_SPIRIT_DEBUG_RULE(CHAR_);
        BOOST_SPIRIT_DEBUG_RULE(WCHART);
        BOOST_SPIRIT_DEBUG_RULE(BOOL_);
        BOOST_SPIRIT_DEBUG_RULE(SHORT_);
        BOOST_SPIRIT_DEBUG_RULE(INT_);
        BOOST_SPIRIT_DEBUG_RULE(LONG_);
        BOOST_SPIRIT_DEBUG_RULE(SIGNED);
        BOOST_SPIRIT_DEBUG_RULE(UNSIGNED);
        BOOST_SPIRIT_DEBUG_RULE(FLOAT_);
        BOOST_SPIRIT_DEBUG_RULE(DOUBLE_);
        BOOST_SPIRIT_DEBUG_RULE(VOID_);
        BOOST_SPIRIT_DEBUG_RULE(AUTO);
        BOOST_SPIRIT_DEBUG_RULE(REGISTER);
        BOOST_SPIRIT_DEBUG_RULE(STATIC);
        BOOST_SPIRIT_DEBUG_RULE(EXTERN);
        BOOST_SPIRIT_DEBUG_RULE(MUTABLE);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE);
        BOOST_SPIRIT_DEBUG_RULE(USING);
        BOOST_SPIRIT_DEBUG_RULE(LEFTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(EXTERN);
        BOOST_SPIRIT_DEBUG_RULE(STRINGLIT);
        BOOST_SPIRIT_DEBUG_RULE(ASM);
        BOOST_SPIRIT_DEBUG_RULE(LEFTPAREN);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTPAREN);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
        BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(CLASS_NAME_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(ENUM_NAME_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(TYPEDEF_NAME_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE_ALIAS_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(ORIGINAL_NAMESPACE_NAME_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE_NAME_HELPER);
        BOOST_SPIRIT_DEBUG_RULE(isNotSpecialToken);
        BOOST_SPIRIT_DEBUG_RULE(SEMICOLON);
        BOOST_SPIRIT_DEBUG_RULE(STRINGLIT);
        BOOST_SPIRIT_DEBUG_RULE(USING);
        BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE);
        BOOST_SPIRIT_DEBUG_RULE(NAMESPACE);
        BOOST_SPIRIT_DEBUG_RULE(LEFTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(FRIEND);
        BOOST_SPIRIT_DEBUG_RULE(TYPEDEF);
        BOOST_SPIRIT_DEBUG_RULE(AUTO);
        BOOST_SPIRIT_DEBUG_RULE(REGISTER);
        BOOST_SPIRIT_DEBUG_RULE(STATIC);
        BOOST_SPIRIT_DEBUG_RULE(EXTERN);
        BOOST_SPIRIT_DEBUG_RULE(MUTABLE);
        BOOST_SPIRIT_DEBUG_RULE(INLINE);
        BOOST_SPIRIT_DEBUG_RULE(VIRTUAL);
        BOOST_SPIRIT_DEBUG_RULE(EXPLICIT);
        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
        BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(ENUM);
        BOOST_SPIRIT_DEBUG_RULE(TYPENAME);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE);
        BOOST_SPIRIT_DEBUG_RULE(LEFTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(COMMA);
        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
        BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
        BOOST_SPIRIT_DEBUG_RULE(TEMPLATE);
        BOOST_SPIRIT_DEBUG_RULE(CHAR_);
        BOOST_SPIRIT_DEBUG_RULE(WCHART);
        BOOST_SPIRIT_DEBUG_RULE(BOOL_);
        BOOST_SPIRIT_DEBUG_RULE(SHORT_);
        BOOST_SPIRIT_DEBUG_RULE(INT_);
        BOOST_SPIRIT_DEBUG_RULE(LONG_);
        BOOST_SPIRIT_DEBUG_RULE(SIGNED);
        BOOST_SPIRIT_DEBUG_RULE(UNSIGNED);
        BOOST_SPIRIT_DEBUG_RULE(FLOAT_);
        BOOST_SPIRIT_DEBUG_RULE(DOUBLE_);
        BOOST_SPIRIT_DEBUG_RULE(VOID_);
        BOOST_SPIRIT_DEBUG_RULE(NOTHING);
        BOOST_SPIRIT_DEBUG_RULE(TYPE_DECL_VALID);
        BOOST_SPIRIT_DEBUG_RULE(TYPE_DECL_VALID_HELP);
    }
}  // namespace cnome

#endif // DECLARATIONS_H

